#ifndef SEGMENTS_H
#define SEGMENTS_H

#include <Types.h>
#include <kstdio.h>

#define SGDT	0	/*Селектор глобальной дискрипторной таблицы*/
#define SLDT	1	/*Селектор локальной дискрипторной таблицы*/

#define UPL	3	/*Уровень привилегий пользователя (user privilege level)*/
#define SPL	0	/*Уровень привилегий системы*/

#define SYS_CODE_SEL	0x60
#define	SYS_DATA_SEL	0x68

#define USR_CODE_SEL	(0x70 | UPL)
#define USR_DATA_SEL	(0x78 | UPL)

#define TSS_SEL			0x80

/*Типы системных дескрипторов сегментов*/
#define SD_RESERV0	0	/*Зарезервирован*/
#define SD_286TSS_AC	1	/*Доступный TSS процессора 286*/
#define SD_LDTTBL	2	/*Таблица LDT*/
#define SD_286TSS_BSY	3	/*Занятый TSS процессора 286*/
#define SD_286CALLGT	4	/*Шлюз вызова процессора 286*/
#define SD_286TSKGT	5	/*Шлюз задачи процессора 286*/
#define SD_286INTGT	6	/*Шлюз прерывания процессора 286*/
#define SD_286TRPGT	7	/*Шлюз ловушки процессора 286*/
#define SD_RESERV1	8	/*Зарезервирован*/
#define SD_486TSS_AC	9	/*Доступный TSS процессора 486*/
#define SD_RESERV2	10	/*Зарезервирован*/
#define SD_486TSS_BSY	11	/*Занятый TSS процессора 486*/
#define SD_486CALLGT	12	/*Шлюз вызова процессора 486*/
#define SD_RESERV3	13	/*Зарезервирован*/
#define SD_486INTGT	14	/*Шлюз прерывания процессора 486*/
#define SD_486TSKGT	15	/*Шлюз задачи процессора 486*/

//!!!!!!!!!!!!!!Доделать для доступных сегментов
/*Типы сегментов памяти*/
#define SDATA_RO	16	/*Сегмент данных, разрешено только считывание*/
#define SDATA_RO_USD	17	/*Используемый сегмент данных, только считывание*/
#define SDATA_RW	18	/*Сегмент данных, разрешено чтение и запись*/
#define SSTACK_RO	20	/*Сегмент стека, только чтение*/
#define SSTACK_RW	22	/*Сегмент стека, чтение и запись*/
#define SCODE_XO	24	/*Секмент кода, только исполнение*/
#define SCODE_XR	26	/*Сегмент кода, исполнение и считывание*/

struct dtr_s{
	uint16 p[3];
};

/*Формат дескриптора сегмента*/
struct __attribute__((packed)) seg_descriptor_t{
    unsigned	sd_lolimit:16;		//Младшие 16 бит поля предела
    unsigned	sd_lobase:24;	//Младшие 24 бита базового адреса
    unsigned	sd_type:5;		//Поле типа
    unsigned	sd_dpl:2;		//Поле уровня привилегий DPL
    unsigned	sd_present:1;		//Бит присутствия
    unsigned	sd_hilimit:4;		//Старшие 8 бит поля предела (всего 24)
    unsigned	sd_xavl:2;		//Зарезарвированный и свободный биты
    unsigned	sd_defsz:1;		//Размер по умолчанию (32 или 16)
    unsigned	sd_gran:1;		//Бит гранулярности
    unsigned	sd_hibase:8;		//Старшие 8 бит базового адреса (всего 32)
};


class Gdt{
	seg_descriptor_t	descs[1024];
	public:
	void setDescriptor(uint32 index, uint32 type, uint32 base, uint32 limit, uint32 pl){
		if(index == 0){
			uint8 *sd = (uint8 *) descs;
			uint8 i;
			for(i = 0; i < 8; i++){ sd[i] = 0;}
		}else{
			descs[index].sd_lolimit = limit & 0xFFFF;
			descs[index].sd_lobase = base & 0xFFFFFF;
			descs[index].sd_type = type;
			descs[index].sd_dpl = pl;
			descs[index].sd_present = 1;
			descs[index].sd_hilimit = limit >> 16;
			descs[index].sd_xavl = 0;
			descs[index].sd_defsz = 1;
			descs[index].sd_gran = 1;
			descs[index].sd_hibase = base >> 24;
		}
	}
	
	void printDescriptor(int pos){
    	uint32 limit = descs[pos].sd_lolimit + (descs[pos].sd_hilimit << 16);
    	uint32 base =  descs[pos].sd_lobase + (descs[pos].sd_hibase << 24);
    	kprintf("Descriptor Nr.%i, sz: %i\n", pos, sizeof(seg_descriptor_t));
    	kprintf("Base: %X, ", base);
    	kprintf("Limit: %X, ", limit);
    	kprintf("Type: %X\n", descs[pos].sd_type);
    	kprintf("dpl: %i, ", descs[pos].sd_dpl);
		kprintf("P: %i\n", descs[pos].sd_present);
	}

};

extern Gdt *gdt;

#endif /* SEGMENTS_H */

